Public Class GPSSentenceHandler

    '   This class recognizes and handles NMEA sentences that are sent to it from a NMEA datasource.
    '   Input can be a serial port but it also be a text-testfile, as long as the filehandler sends separate NMEAsentences to this GPSSentenceHandler.
    '   Every sentence is expected to be an array of strings, separated by comma's. That is exactly the format the data has when it is  received from the datasource.
    '   Splitting the NMEA sentence is straightforward: every recognized sentence is explained in the parsing routine. 
    '   Events are raised after picking the right string from the array.
    '   The class fires several events, depending on the sentences sent to it and the data contained in that sentence.

    '   Input: NMEA sentence from a NMEA source.
    '   Output: nothing.

    'version 0.2
    'date: 2007-10-19
    'developer: Peter C. Klein
    'This is the second design version and the first published version.
    'Not all possible NMEA sentences are defined in this version, and not all available data is parsed and translated into a raised event. 
    'Others are invited to expand the number of NMEA sentences and to expand the number of event raised.

    Public Event NewWindDirection(ByVal WindDirection As String)
    Public Event NewWindForceInKM(ByVal WindForceInKM As String)
    Public Event NewWindForceInKnots(ByVal WindForceInKnots As String)
    Public Event NewWindForceInMSec(ByVal WindForceInMSec As String)
    Public Event NewDepthInFeet(ByVal NumberOfFeet As String)
    Public Event NewDepthInMeters(ByVal NumberOfMeters As String)
    Public Event NewDepthInFathoms(ByVal NumberOfFathoms As String)
    Public Event NewPositionLatitude(ByVal PositionLatitude As String)
    Public Event NewPositionLongitude(ByVal PositionLongitude As String)
    Public Event NewLogSpeedInKnots(ByVal LogSpeedInKnots As String)
    Public Event NewGroundSpeedInKnots(ByVal GroundSpeedInKnots As String)
    Public Event NewWaterTemperature(ByVal WaterTemperature As String)

    Public Sub ParseSerialData(ByVal NMEASentence() As String)
        Try
            SentenceType = Microsoft.VisualBasic.Mid(NMEASentence(0), 4, 3)

            Select Case SentenceType
                Case "APA"
                    ParseAPA(NMEASentence)
                Case "APB"
                    ParseAPB(NMEASentence)
                Case "BWC"
                    ParseBWC(NMEASentence)
                Case "DBT"
                    ParseDBT(NMEASentence)
                Case "GLL"
                    ParseGLL(NMEASentence)
                Case "HDM"
                    ParseHDM(NMEASentence)
                Case "MTW"
                    ParseMTW(NMEASentence)
                Case "RMB"
                    ParseRMB(NMEASentence)
                Case "RMC"
                    ParseRMC(NMEASentence)
                Case "VHW"
                    ParseVHW(NMEASentence)
                Case "VWR"
                    ParseVWR(NMEASentence)
                Case "VTG"
                    ParseVTG(NMEASentence)
                Case "XTE"
                    ParseXTE(NMEASentence)
                Case Else
                    My.Application.Log.WriteEntry("Unknown Sentence Type '" & SentenceType & "'.")
            End Select

        Catch ex As Exception
            My.Application.Log.WriteEntry("Sentence incorrect: " & ex.Message)
        End Try

    End Sub

    Public Sub ParseAPA(ByVal MyNMEASentence As String())

        '$GPAPB,A,A,00.00,L,N,V,V,042.3,M,WPT001 *6F
        'where:
        'APA	        Autopilot format B
        'A		            Loran-C blink/SNR warning, general warning 
        'A		            Loran-C cycle warning 
        '00.00	        cross-track error distance 
        'L		            steer Right to correct (or L for Left) 
        'N		            cross-track error units - nautical miles (K for kilometers) 
        'V		            arrival alarm - circle 
        'V		            arrival alarm - perpendicular 
        '042.3          bearing origin to destination 
        'M		            magnetic bearing, 
        'WPT001		destination waypoint ID 
        '*6C		        checksum

    End Sub

    Public Sub ParseAPB(ByVal MyNMEASentence As String())

        '$GPAPB,A,A,00.00,L,N,V,V,042.3,M,WPT001 ,042.3,M,042.3,M*6C
        'where:
        'APB		        Autopilot format B
        'A		            Loran-C blink/SNR warning, general warning 
        'A		            Loran-C cycle warning 
        '00.00	        cross-track error distance 
        'L		            steer Right to correct (or L for Left) 
        'N		            cross-track error units - nautical miles (K for kilometers) 
        'V		            arrival alarm - circle 
        'V		            arrival alarm - perpendicular 
        '042.3          bearing origin to destination 
        'M		            magnetic bearing, 
        'WPT001		destination waypoint ID 
        '042.3          bearing present position to destination 
        'M		            magnetic bearing
        '042.3          heading to steer
        'M		            magnetic heading to steer
        '*6C		        checksum

    End Sub

    Public Sub ParseBWC(ByVal MyNMEASentence As String())
        'BWC - Bearing & Distance to Waypoint using a Great Circle route. 
        'Time (UTC) and distance & bearing to, and location of a specified waypoint from present position along the great circle path. 
        '$GPBWC,020315,3649.647,S,17449.861,E,061.8,T,042.3,M,004.2,N,WPT001 *78

        'where:
        '        BWC		    Bearing and distance to waypoint - great circle
        '        020315		UTC time of fix 02:03:15
        '        3649.647    Latitude of waypoint
        '        S                 South (North)
        '        17449.861	Longitude of waypoint
        '        E                 East (West)
        '        061.8   		Bearing to waypoint, degrees true
        '        T                 degrees True
        '        042.3   		Bearing to waypoint, degrees magnetic
        '        M                 degrees Magnetic
        '        004.2		    Distance to waypoint, Nautical miles
        '        N                 Nautical Miles
        '        WPT001 		Waypoint ID
        '        *78		        checksum

    End Sub

    Public Sub ParseDBT(ByVal MyNMEASentence As String())
        'DBT	depth below transducer

        '        $IIDBT,008.9,f,002.7,M,001.4,F*10
        '        where:

        '0:        DBT(berichtkenmerk)
        '1	        008.9		008.9 depth in feet
        '2:        f(feet)
        '3	        002.7		002.7 depth in meters
        '4:        M(Meters)
        '5	        001.4		001.4 depth in fathoms
        '6:        F(Fathoms)
        '7	        *10		    checksum data

        RaiseEvent NewDepthInFeet(MyNMEASentence(1))
        RaiseEvent NewDepthInMeters(MyNMEASentence(3))
        RaiseEvent NewDepthInFathoms(MyNMEASentence(5))

    End Sub

    Public Sub ParseGLL(ByVal MyNMEASentence As String())
        'GLL - Geographic Latitude and Longitude is a holdover from Loran data and some old units may not send 
        'the time and data active information if they are emulating Loran data. If a gps is emulating Loran data they may use the LC Loran prefix instead of GP. 

        '$GPGLL,3651.625,S,17445.246,E,020312.00,A*18
        'Where:

        'GLL          	    Geographic position, Latitude and Longitude
        '3651.625   	    Latitude 36 deg. 51.625 min. 
        'S                     South (North)
        '17445.246,E  	Longitude 174 deg. 45.246 min. 
        'E                     East (West)
        '020312.00    	Fix taken at 02:03:12.00 UTC
        'A            		    Data Active or V (void)
        '*18          	    checksum data

    End Sub

    Public Sub ParseHDM(ByVal MyNMEASentence As String())
        'HDM heading, magnetic

        '$IIHDM,123,M*0C
        'Where

        'HDM		magnetic course
        '123		    heading in degrees to magnetic North
        '*0C		    checksum data

    End Sub

    Public Sub ParseMTW(ByVal MyNMEASentence As String())
        'MTW	sea temperature

        '$IIMTW,000,C*3D
        'where

        '0     MTW	    temperature of the water
        '1     000	    temperature in degrees
        '2     C	        degrees Celcius
        '3     *3D	    checksum data

        RaiseEvent NewWaterTemperature(MyNMEASentence(1))

    End Sub

    Public Sub ParseRMB(ByVal MyNMEASentence As String())
        '        RMB - The recommended minimum navigation sentence is sent whenever a route or a goto is active. 
        '        On some systems it is sent all of the time with null data. 
        '        The Arrival alarm flag is similar to the arrival alarm inside the unit and can be decoded to drive an external alarm. 
        '        Note the use of leading zeros in this message to preserve the character spacing. 
        '        This is done, I believe, because some autopilots may depend on exact character spacing. 

        '$GPRMB,A,00.66,L,WPT001,WPT002,3649.647,S,17449.861,E,004.2,061.8,000.0,V*7D
        'where:

        'RMB		    Recommended minimum navigation information
        'A			        Data status A = OK, V = Void (warning)
        '00.66		    Cross-track error (nautical miles, 9.99 max),
        'L                 	steer Left to correct (or R = right)
        'WPT001		Origin waypoint ID
        'WPT002		Destination waypoint ID
        '3649.647	 	Destination waypoint latitude 49 deg. 17.24 min. (N,S)
        'S                 (N)orth or (S)outh
        '17449.861	Destination waypoint longitude 123 deg. 09.57 min. (E,W)
        'E                 (E)ast or (W)est
        '004.2		    Range to destination, nautical miles (999.9 max)
        '061.8		    True bearing to destination
        '000.0		    Velocity towards destination, knots
        'V			        Arrival alarm  A = arrived, V = not arrived
        '*7D		        checksum

    End Sub

    Public Sub ParseRMC(ByVal MyNMEASentence As String())
        '   RMC - NMEA has its own version of essential gps pvt (position, velocity, time) data. It is called RMC, 
        '   The Recommended Minimum, which will look similar to: 

        '$GPRMC,020314.00,A,3651.625,S,17445.246,E,000.0,000.0,230197,19.5,E*71
        'Where:

        '0         RMC		        Recommended Minimum sentence C
        '1         020314.00	Fix taken at 02:03:14.00 UTC
        '2         A			        Status A=active or V=Void.
        '3         3651.625	    Latitude 36 deg 51.625' S (N)
        '4         S                 S (N)
        '5         17445.246	Longitude 174 deg 45.246' 
        '6         E                  E (W)
        '7         000.0		    Speed over the ground in knots
        '8         000.0		    Track angle in degrees True
        '9         230197		    Date - 23rd of January 1997
        '10       19.5		        Magnetic Variation (E / W)
        '11       E                  (E / W)
        '12       *71		        The checksum data, always begins with *



    End Sub

    Public Sub ParseVHW(ByVal MyNMEASentence As String())
        'VHW	logsnelheid en koers (magnetische en ware koers)

        '$IIVHW,061.8,T,042.3,M,06.14,N,04.34,K*55
        'where:

        '0     VHW	    logspeed and heading
        '1     061.8	    degrees 061.8
        '2     T	            true heading
        '3     042.3	    degrees 042.3
        '4      M	            magnetic heading
        '5      00.00	    speed
        '6      N	            in knots
        '7      00.00	    speed
        '8      K	            in kilometers per hour
        '9      *55	        checksum data

        RaiseEvent NewLogSpeedInKnots(MyNMEASentence(5))
    End Sub

    Public Sub ParseVWR(ByVal MyNMEASentence As String())
        'VWR	apparent wind angle and wind speed
        
        '$IIVWR,004,L,11.5,N,05.9,M,021.4,K*43
        'where

        '0     VWR    apparent wind angle and wind speed
        '1     004	    aantal graden windhoek van de schijnbare wind
        '2     L         (L)inks of (R)echts van de boeg inkomende richting
        '3     11.5    sterkte in knopen
        '4     N         kNopen
        '5     06.7    sterkte in Meters per seconde
        '6     M         (M)eters per seconde
        '7     021.4  snelheid in kilometers per uur
        '8     K         (K)ilometers
        '9     *43	    controlegetal 

        RaiseEvent NewWindDirection(MyNMEASentence(1))
        RaiseEvent NewWindForceInKnots(MyNMEASentence(3))
        RaiseEvent NewWindForceInMSec(MyNMEASentence(5))
        RaiseEvent NewWindForceInKM(MyNMEASentence(7))


    End Sub

    Public Sub ParseVTG(ByVal MyNMEASentence As String())
        'VTG - Velocity made good. 

        '$GPVTG,000.0,T,340.5,M,000.0,N,000.0,K*4C
        'where:

        '0     VTG	    Track made good and ground speed
        '1     000.0   True track made good
        '2     T	        True track made good (degrees)
        '3     340.5   Magnetische track made good
        '4     M	        Magnetische track made good
        '5     000.0   Ground speed in knots
        '6     N	        Ground speed, knots
        '7     0000.0 Ground speed
        '8     K    	    kilometers per hour
        '9     *4C      Checksum data

        RaiseEvent NewGroundSpeedInKnots(MyNMEASentence(5))
    End Sub

    Public Sub ParseXTE(ByVal MyNMEASentence As String())
        'XTE - Measured cross track error is a small subset of the RMB message for compatibility with some older equipment designed to work with Loran. 
        'Note that the same limitations apply to this message as the ones in the RMB since it is expected to be decoded by an autopilot. 

        '$GPXTE,A,A,00.00,L,N*5E
        'Where:

        '0    XTE		Cross track error, measured
        '1     A		    General warning flag V = warning
        '2     A		    Not used for GPS
        '3     00.00	cross track error distance
        '4     L		    Steer left to correct error (or R for right)
        '5     N		    Distance units - Nautical miles
        '6     *5E		checksum data

    End Sub

End Class
